import { observe } from "./observer/index.js";

export function initState(vm) {
  // vm  => 实例化对象
  const opts = vm.$options; // 配置项
  // 配置项里面是否提供了data
  if (opts.data) {
    // 处理数据的响应式
    initData(vm);
  }
  // computed ... watch
}

function initProps() {
  //   // 初始化props
}

function initMethod() {}

// 执行数据的代理，通过this.key 可以拿到data里面的属性
function proxy(target, property, key) {
  // 如果从vm获取key（数据的键名）会触发get
  // target >> vm key >> 对象对象的key
  // this.msg
  // this._data.msg
  // 所有对示例的操作，转化成对数据对象的操作
  // this.aa = 'aa';
  // this.timer = '';
  Object.defineProperty(target, key, { // target: vm  key: name 对象的属性名
    get() {
      // 获取属性的时候触发
      // 如果在target上获取key的时候会触发这里的get
      // 如果在this上获取data里面的属性名的时候就会触发
      // 如果通过this.属性名获取data里面的属性的时候，会代理到_data里面
      return target[property][key];
    },
    // 设置数据的时候会触发set
    // this.msg = 'newValue' >> this_data.msg = 'newValue'
    set(newValue) {
      target[property][key] = newValue;
    },
  });
}

function initData(vm) {
  // vm实例化对象 $options传入的配置项
  // 数据响应式原理
  let data = vm.$options.data; // 用户传入的数据
  // this.data = vm.$options.data
  // vm._data 就是检测后的数据了

  // data(); 函数的单独调用，全局对象，默认开启了严格模式，data函数内部的this执行vm实例
  data = vm._data = typeof data === "function" ? data.call(vm) : data;
  // this[data里面的key] => this._data[data里面的key]
  for (let key in data) {
    proxy(vm, "_data", key);
  }
  // 效果：已经可以使用this.key 获取到data里面的属性了，也可以设置属性了，经过了数据的代理
  observe(data); // 观测这个数据
}
